#include "modelclass.h"


ModelClass::ModelClass(float pos_x, float pos_y ,float pos_z, float scale_x, float scale_y ,float scale_z):m_vertexBuffer(0),m_indexBuffer(0) 
{
	D3DXMatrixIdentity(&m_transformation);
	SetScale(scale_x,scale_y,scale_z);
	SetPosition(pos_x,pos_y,pos_z);
}

bool ModelClass::Initialize(ID3D11Device* device)
{
	bool result;
	result = InitializeBuffers(device);
	return result;
}

void ModelClass::Shutdown()
{
	ShutdownBuffers();
}

void ModelClass::Render(ID3D11DeviceContext* deviceContext)
{
	RenderBuffers(deviceContext);
}

int ModelClass::GetIndexCount()
{
	return m_indexCount;
}

bool ModelClass::InitializeBuffers(ID3D11Device* device)
{
	VertexType* vertices;
	D3D11_BUFFER_DESC vercolorBufferDesc, indexBufferDesc;
	D3D11_SUBRESOURCE_DATA vercolorData, indexData;
	HRESULT result;

	m_vertexCount = 24;
	m_indexCount = 36;

	vertices = new VertexType[m_vertexCount];
	if(!vertices)
	{
		return false;
	}

	vertices[0].position = D3DXVECTOR3( -1.0f,  1.0f, -1.0f );		vertices[0].tex = D3DXVECTOR2(0.0f, 0.0f);
	vertices[1].position = D3DXVECTOR3(  1.0f,  1.0f, -1.0f );		vertices[1].tex = D3DXVECTOR2(1.0f, 0.0f);
	vertices[2].position = D3DXVECTOR3(  1.0f,  1.0f,  1.0f );		vertices[2].tex = D3DXVECTOR2(1.0f, 1.0f);
	vertices[3].position = D3DXVECTOR3( -1.0f,  1.0f,  1.0f );		vertices[3].tex = D3DXVECTOR2(0.0f, 1.0f);

	vertices[4].position = D3DXVECTOR3( -1.0f,  -1.0f, -1.0f );		vertices[4].tex = D3DXVECTOR2(0.0f, 0.0f);
	vertices[5].position = D3DXVECTOR3(  1.0f,  -1.0f, -1.0f );		vertices[5].tex = D3DXVECTOR2(1.0f, 0.0f);
	vertices[6].position = D3DXVECTOR3(  1.0f,  -1.0f,  1.0f );		vertices[6].tex = D3DXVECTOR2(1.0f, 1.0f);
	vertices[7].position = D3DXVECTOR3( -1.0f,  -1.0f,  1.0f );		vertices[7].tex = D3DXVECTOR2(0.0f, 1.0f);

	vertices[8].position = D3DXVECTOR3( -1.0f,  -1.0f, 1.0f );		vertices[8].tex = D3DXVECTOR2(0.0f, 0.0f);
	vertices[9].position = D3DXVECTOR3(  -1.0f,  -1.0f, -1.0f );	vertices[9].tex = D3DXVECTOR2(1.0f, 0.0f);
	vertices[10].position = D3DXVECTOR3(  -1.0f,  1.0f,  -1.0f );	vertices[10].tex = D3DXVECTOR2(1.0f, 1.0f);
	vertices[11].position = D3DXVECTOR3( -1.0f,   1.0f,  1.0f );	vertices[11].tex = D3DXVECTOR2(0.0f, 1.0f);

	vertices[12].position = D3DXVECTOR3( 1.0f,  -1.0f, 1.0f );		vertices[12].tex = D3DXVECTOR2(0.0f, 0.0f);
	vertices[13].position = D3DXVECTOR3( 1.0f,  -1.0f, -1.0f );		vertices[13].tex = D3DXVECTOR2(1.0f, 0.0f);
	vertices[14].position = D3DXVECTOR3( 1.0f,   1.0f, -1.0f );		vertices[14].tex = D3DXVECTOR2(1.0f, 1.0f);
	vertices[15].position = D3DXVECTOR3( 1.0f,   1.0f,  1.0f );		vertices[15].tex = D3DXVECTOR2(0.0f, 1.0f);

	vertices[16].position = D3DXVECTOR3( -1.0f,  -1.0f, -1.0f );	vertices[16].tex = D3DXVECTOR2(0.0f, 0.0f);
	vertices[17].position = D3DXVECTOR3( 1.0f,  -1.0f, -1.0f );		vertices[17].tex = D3DXVECTOR2(1.0f, 0.0f);
	vertices[18].position = D3DXVECTOR3( 1.0f,   1.0f, -1.0f );		vertices[18].tex = D3DXVECTOR2(1.0f, 1.0f);
	vertices[19].position = D3DXVECTOR3( -1.0f,   1.0f,  -1.0f );	vertices[19].tex = D3DXVECTOR2(0.0f, 1.0f);

	vertices[20].position = D3DXVECTOR3( -1.0f,  -1.0f, 1.0f );		vertices[20].tex = D3DXVECTOR2(0.0f, 0.0f);
	vertices[21].position = D3DXVECTOR3( 1.0f,  -1.0f, 1.0f );		vertices[21].tex = D3DXVECTOR2(1.0f, 0.0f);
	vertices[22].position = D3DXVECTOR3( 1.0f,   1.0f, 1.0f );		vertices[22].tex = D3DXVECTOR2(1.0f, 1.0f);
	vertices[23].position = D3DXVECTOR3( -1.0f,   1.0f,  1.0f );	vertices[23].tex = D3DXVECTOR2(0.0f, 1.0f);



	//Index buffer
	unsigned long indices[] = 
	{
		3,1,0, // Prima faccia
		2,1,3,

		6,4,5, // Seconda faccia
		7,4,6,

		11,9,8, // Terza faccia
		10,9,11,

		14,12,13, // Quarta faccia
		15,12,14,

		19,17,16, // Quinta faccia
		18,17,19,

		22,20,21, // Sesta faccia
		23,20,22
	};

	for (int i=0; i != 12; ++i )
	{
		int v0 = indices[i*3+0];
		int v1 = indices[i*3+1];
		int v2 = indices[i*3+2];

		ComputeTangentBasis(vertices[v0].position, vertices[v1].position, vertices[v2].position, vertices[v0].tex, vertices[v1].tex, vertices[v2].tex, 
			vertices[v0].norm, vertices[v0].tan, vertices[v0].binorm);
		vertices[v1].norm = vertices[v0].norm; vertices[v1].tan = vertices[v0].tan; vertices[v1].binorm = vertices[v0].binorm;
		vertices[v2].norm = vertices[v0].norm; vertices[v2].tan = vertices[v0].tan; vertices[v2].binorm = vertices[v0].binorm;
	}

	vercolorBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	vercolorBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount;
	vercolorBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vercolorBufferDesc.CPUAccessFlags = 0;
	vercolorBufferDesc.MiscFlags = 0;
	vercolorBufferDesc.StructureByteStride = 0;

	vercolorData.pSysMem = vertices;
	vercolorData.SysMemPitch = 0;
	vercolorData.SysMemSlicePitch = 0;

	result = device->CreateBuffer(&vercolorBufferDesc, &vercolorData, &m_vertexBuffer);
	if(FAILED(result))
	{
		return false;
	}

	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;

	indexData.pSysMem = indices;
	result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);
	if(FAILED(result))
	{
		return false;
	}

	delete [] vertices;
	vertices = 0;

	return true;
}

void ModelClass::ShutdownBuffers()
{
	if(m_indexBuffer)
	{
		m_indexBuffer->Release();
		m_indexBuffer = 0;
	}

	if(m_vertexBuffer)
	{
		m_vertexBuffer->Release();
		m_vertexBuffer = 0;
	}

	return;
}

void ModelClass::RenderBuffers(ID3D11DeviceContext* deviceContex)
{
	unsigned int stride;
	unsigned int offset;

	stride = sizeof(VertexType); 
	offset = 0;
	deviceContex->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);
	deviceContex->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
}

void ModelClass::ComputeTangentBasis(const D3DXVECTOR3& P1, const D3DXVECTOR3& P2, const D3DXVECTOR3& P3, 
	const D3DXVECTOR2& UV1, const D3DXVECTOR2& UV2, const D3DXVECTOR2& UV3,
	D3DXVECTOR3 &o_normal, D3DXVECTOR3 &o_tangent, D3DXVECTOR3 &o_bitangent )
{

	D3DXVECTOR3 Edge1 = P2 - P1;
	D3DXVECTOR3 Edge2 = P3 - P1;	
	D3DXVECTOR2 Edge1uv = UV2 - UV1;
	D3DXVECTOR2 Edge2uv = UV3 - UV1;

	D3DXVec3Cross(&o_normal, &Edge1, &Edge2);
	D3DXVec3Normalize(&o_normal, &o_normal);

	float cp = Edge1uv.y * Edge2uv.x - Edge1uv.x * Edge2uv.y;

	if ( cp != 0.0f ) 
	{
		float mul = 1.0f / cp;
		o_tangent   = (Edge1 * -Edge2uv.y + Edge2 * Edge1uv.y) * mul;
		o_bitangent = (Edge1 * -Edge2uv.x + Edge2 * Edge1uv.x) * mul;	  

		D3DXVec3Normalize(&o_tangent, &o_tangent);
		D3DXVec3Normalize(&o_bitangent, &o_bitangent);
	}
}